/*
 * @Author: wuqingchun
 * @Date: 2024-07-23 13:29:06
 * @Description: 
 * @LastEditors: wuqingchun
 * @LastEditTime: 2024-07-26 17:09:58
 */

#include "common.h"
#include "page_cache.h"

PageCache PageCache::m_objInstance = {};

Span* PageCache::NewSpan(size_t ulPageNum)
{
    //printf("Get %lu pages from PageCache\n", ulPageNum);

    if (ulPageNum == 0)
    {
        return nullptr;
    }
    
    if (ulPageNum > SizeAlignStrategy::PAGE_NUM_MAX)
    {
        return __GetLargeSpan(ulPageNum);
    }

    size_t ulIndex = ulPageNum - 1;
    // 从包含相同页的Span 链中获取一个Span
    if (!m_arrSpanList[ulIndex].Empty())
    {
        Span* pstSpan = m_arrSpanList[ulIndex].PopFront();
        // m_mapSpanByPageID[pstSpan->ulPageID] = pstSpan;
        // m_mapSpanByPageID[pstSpan->ulPageID + ulIndex] = pstSpan;

        return pstSpan;
    }

    // 从包含更多的页的Span链中获取一个 Span
    for (size_t ulIndex = ulPageNum; ulIndex < SizeAlignStrategy::PAGE_NUM_MAX; ulIndex++)
    {
        if (!m_arrSpanList[ulIndex].Empty())
        {
            Span* pstBig = m_arrSpanList[ulIndex].PopFront();
            // 需要进行切分
            Span* pstSmall = m_objSpanPool.New();
            pstSmall->ulPageID = pstBig->ulPageID;
            pstSmall->ulPageNum = ulPageNum;

            pstBig->ulPageID += ulPageNum;
            pstBig->ulPageNum -= ulPageNum;

            m_arrSpanList[pstBig->ulPageNum - 1].PushFront(pstBig);

            // m_mapSpanByPageID[pstBig->ulPageID] = pstSmall;
            // m_mapSpanByPageID[pstSmall->ulPageID + ulPageNum - 1] = pstSmall;

            return pstSmall;
        }
    }

    // 从系统中申请 Span
    void* pPage = OsAlloc(SizeAlignStrategy::PAGE_NUM_MAX);
    if (pPage == nullptr)
    {
        return nullptr;
    }

    //printf("OsAlloc: %p\n", pPage);

    Span* pstSpan = m_objSpanPool.New();
    if (pstSpan == nullptr)
    {
        OsFree(pPage, SizeAlignStrategy::PAGE_NUM_MAX);
        return nullptr;
    }

    pstSpan->ulPageID = (unsigned long)pPage >> PAGE_SHIFT;
    pstSpan->ulPageNum = SizeAlignStrategy::PAGE_NUM_MAX;

    // 插入到 最大的 Span 链中
    m_arrSpanList[SizeAlignStrategy::PAGE_NUM_MAX - 1].PushFront(pstSpan);

    return NewSpan(ulPageNum);
}

Span* PageCache::__GetLargeSpan(size_t ulPageNum)
{
    // 需要的内存页的数量大于 PAGE_NUM_MAX，PageCache无法提供，需要从系统直接获取
    void* pPage = OsAlloc(ulPageNum);
    if (pPage == nullptr)
    {
        return nullptr;
    }

    Span* pstSpan = m_objSpanPool.New();
    if (pstSpan == nullptr)
    {
        OsFree(pPage, ulPageNum);
        return nullptr;
    }
    
    // 根据页首地址确定页号
    pstSpan->ulPageID = ((unsigned long)pPage >> PAGE_SHIFT);
    pstSpan->ulPageNum = ulPageNum;

    m_mapSpanByPageID[pstSpan->ulPageID] = pstSpan;
    m_mapSpanByPageID[pstSpan->ulPageID + ulPageNum - 1] = pstSpan;

    return pstSpan;
}